home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
devel
/
vbcc-68k-src
/
vlink
/
targets.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-01
|
26KB
|
906 lines
/* $VER: vlink targets.c V0.6c (05.02.99)
*
* This file is part of vlink, a portable linker for multiple
* object formats.
* Copyright (c) 1997-99 Frank Wille
*
* vlink is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
* vlink may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.6c (05.02.99) phx
* ctors/dtors sections always start with 0xffffffff to provide
* compatibility with most file formats (e.g. ELF).
* v0.6a (19.12.98) phx
* Support for little endian object file formats.
* readsection()/writesection() obey current endianess of linking
* process.
* make_priptr_objects() updates linker symbols during add_da-
* ta_section().
* v0.6 (24.10.98) phx
* find_lnksec() finds a LinkedSection by its name and/or type
* (needed for ELF small data support).
* New target elf32powerup, which supports the PPC coprocessor
* boards from Phase5.
* v0.5e (05.10.98) phx
* new_priptr(), add_priptrs(), make_priptr_objects(). Support for
* artificial sections and objects, containing longwords sorted by
* priority. These sections are automatically terminated by a NULL
* pointer entry. Currently only used by ados-target for constructor
* and destructor function pointer lists (__ctors, __dtors).
* v0.5c (08.07.98) phx
* art_objunit() creates an artificial ObjectUnit + LinkFile.
* v0.5 (27.06.98) phx
* addlnksymbol(), findlnksymbol() for target-specific linker
* symbol support.
* smalldata_section() returns a pointer to the first section,
* which is referenced base relative.
* v0.3 (17.04.98) phx
* addlocsymbol() allows multiple defintions of local
* symbols with the same name.
* addreloc() adds another relocation to a section.
* relocsize() determines size in bytes of a relocation type.
* addxref() requires the addend as additional argument.
* ar-support functions for library archives.
* v0.1 (27.02.98) phx
* First version that seems to link AmigaOS ADOS and EHF
* objects and libraries. Many common features, like linking
* sections together which have relative references, are
* still missing. Also, PowerPC-ELF32 support is about to come.
* v0.0 (05.08.97) phx
* File created.
*/
#define TARGETS_C
#include "vlink.h"
unsigned long findsecbase(struct GlobalVars *,char *);
struct Symbol *findsymbol(struct GlobalVars *,char *name);
struct Symbol *addsymbol(struct GlobalVars *,struct Section *,char *,
uint32,uint8,uint8,uint8,uint8,uint32);
void addlocsymbol(struct GlobalVars *,struct Section *,char *,uint32,
uint8,uint8,uint8,uint32);
void addglobsym(struct GlobalVars *,struct Symbol *);
struct Symbol *addlnksymbol(struct FFFuncs *,struct Section *,char *,
uint32,uint8,uint8,uint8,uint8,uint32);
struct Symbol *findlnksymbol(struct FFFuncs *,char *);
void addreloc(struct Section *,struct Section *,uint32,uint32,uint8,int32);
void addxref(struct GlobalVars *,struct Section *,char *,uint32,uint8,
uint8,int32);
int32 readsection(struct GlobalVars *,uint8 *,uint8);
void writesection(struct GlobalVars *,uint8 *,uint8,uint32);
uint8 relocsize(uint8);
struct Section *create_section(struct ObjectUnit *,char *,uint8 *,
unsigned long);
struct Section *find_sect_type(struct ObjectUnit *,uint8,uint8);
struct Section *find_sect_id(struct ObjectUnit *,uint32);
struct LinkedSection *find_lnksec(struct GlobalVars *,char *,uint8,
uint8,uint8);
struct LinkedSection *smalldata_section(struct GlobalVars *);
void add_objunit(struct GlobalVars *,struct ObjectUnit *,bool);
struct ObjectUnit *create_objunit(struct LinkFile *,char *);
struct ObjectUnit *art_objunit(char *,uint8 *,unsigned long,uint8);
void new_priptr(struct ObjectUnit *,char *,char *,int,char *,uint32);
void add_priptrs(struct GlobalVars *,struct ObjectUnit *);
void make_priptr_objects(struct GlobalVars *);
bool ar_init(struct ar_info *,char *,unsigned long,char *);
bool ar_extract(struct ar_info *);
static struct Section *getsecptr(struct list *,uint32);
static struct Section *add_data_section(struct GlobalVars *,
struct ObjectUnit *,char *,uint8 *,
unsigned long);
struct FFFuncs *fff[] = {
#ifdef ADOS
&fff_amigaos,
#endif
#ifdef EHF
&fff_ehf,
#endif
#ifdef ELF32_PPC_BE
&fff_elf32ppcbe,
#endif
#ifdef ELF32_POWERUP
&fff_elf32powerup,
#endif
NULL
};
const char *sym_type[] = { "undef","abs","reloc","common" };
const char *sym_info[] = { ""," object"," function"," section"," file" };
const char *sym_bind[] = { "","local ","global ","weak " };
unsigned long findsecbase(struct GlobalVars *gv,char *name)
/* scan the secbases list for a base address definition */
{
struct SecBase *sb = gv->secbases;
while (sb) {
if (!strcmp(name,sb->name))
return (sb->base);
sb = sb->next;
}
}
struct Symbol *findsymbol(struct GlobalVars *gv,char *name)
/* return pointer to Symbol, if present */
{
struct Symbol *sym = gv->symbols[elf_hash(name)%SYMHTABSIZE];
while (sym) {
if (!strcmp(name,sym->name))
return (sym); /* symbol found! */
sym = sym->glob_chain;
}
return (NULL);
}
struct Symbol *addsymbol(struct GlobalVars *gv,struct Section *s,char *name,
uint32 val,uint8 type,uint8 flags,uint8 info,
uint8 bind,uint32 size)
/* Define a new symbol. If defined twice in the same object unit, then */
/* return a pointer to its first definition. Defining the symbol twice */
/* globally, is only allowed in different object units of a library. */
{
struct Symbol *sym;
struct ObjectUnit *ou = s->obj;
struct Symbol **chain = &s->obj->objsyms[elf_hash(name)%OBJSYMHTABSIZE];
while (sym = *chain) {
if (!strcmp(name,sym->name))
return (sym); /* symbol already defined - don't define it twice */
/* The target-specific routines have to handle this case. */
chain = &sym->obj_chain;
}
*chain = sym = alloc(sizeof(struct Symbol));
sym->glob_chain = sym->obj_chain = NULL;
sym->name = name;
sym->value = val;
sym->relsect = s;
sym->type = type;
sym->flags = flags;
sym->info = info;
sym->bind = bind;
sym->size = size;
if (bind==SYMB_GLOBAL || bind==SYMB_WEAK)
addglobsym(gv,sym);
return (NULL); /* ok, new symbol was created */
}
void addlocsymbol(struct GlobalVars *gv,struct Section *s,char *name,
uint32 val,uint8 type,uint8 flags,uint8 info,uint32 size)
/* Define a new local symbol. Local symbols are allowed to be */
/* multiply defined. */
{
struct Symbol *sym;
struct Symbol **chain = &s->obj->objsyms[elf_hash(name)%OBJSYMHTABSIZE];
while (sym = *chain)
chain = &sym->obj_chain;
*chain = sym = alloc(sizeof(struct Symbol));
sym->glob_chain = sym->obj_chain = NULL;
sym->name = name;
sym->value = val;
sym->relsect = s;
sym->type = type;
sym->flags = flags;
sym->info = info;
sym->bind = SYMB_LOCAL;
sym->size = size;
}
void addglobsym(struct GlobalVars *gv,struct Symbol *newsym)
/* insert symbol into global symbol hash table */
{
struct Symbol **chain = &gv->symbols[elf_hash(newsym->name)%SYMHTABSIZE];
struct Symbol *sym;
struct ObjectUnit *newou = newsym->relsect->obj;
while (sym = *chain) {
if (!strcmp(newsym->name,sym->name)) {
if (sym->bind == SYMB_GLOBAL) {
/* symbol already defined with global binding */
if (newsym->bind==SYMB_GLOBAL && newou->lnkfile->type<ID_LIBBASE) {
if (newsym->type==SYM_COMMON && sym->type==SYM_COMMON) {
if (newsym->size > sym->size) {
/* replace by common symbol with bigger size */
newsym->glob_chain = sym->glob_chain;
sym->glob_chain = NULL;
break;
}
}
else
/* Global symbol "x" is already defined in... */
error(19,newou->lnkfile->pathname,newsym->name,newou->objname,
sym->relsect->obj->lnkfile->pathname,
sym->relsect->obj->objname);
}
return; /* don't replace global symbols */
}
else {
if (newsym->bind == SYMB_WEAK)
return; /* don't replace weak by weak */
/* replace weak symbol */
newsym->glob_chain = sym->glob_chain;
sym->glob_chain = NULL;
break;
}
}
chain = &sym->glob_chain;
}
*chain = newsym;
if (trace_sym_access(gv,newsym->name))
fprintf(stderr,"Symbol %s defined in section %s in %s\n",
newsym->name,newsym->relsect->name,getobjname(newou));
}
struct Symbol *addlnksymbol(struct FFFuncs *fffptr,struct Section *s,
char *name,uint32 val,uint8 type,uint8 flags,
uint8 info,uint8 bind,uint32 size)
/* Define a new, target-specific, linker symbol. */
{
struct Symbol *sym;
struct Symbol **chain;
if (fffptr->lnksyms == NULL)
fffptr->lnksyms = alloc_hashtable(LNKSYMHTABSIZE);
chain = &fffptr->lnksyms[elf_hash(name)%LNKSYMHTABSIZE];
while (sym = *chain)
chain = &sym->obj_chain;
*chain = sym = alloc(sizeof(struct Symbol));
sym->glob_chain = sym->obj_chain = NULL;
sym->name = name;
sym->value = val;
sym->relsect = s;
sym->type = type;
sym->flags = flags;
sym->info = info;
sym->bind = bind;
sym->size = size;
return (sym);
}
struct Symbol *findlnksymbol(struct FFFuncs *fffptr,char *name)
/* return pointer to Symbol, if present */
{
struct Symbol *sym;
if (fffptr->lnksyms) {
sym = fffptr->lnksyms[elf_hash(name)%LNKSYMHTABSIZE];
while (sym) {
if (!strcmp(name,sym->name))
return (sym); /* symbol found! */
sym = sym->obj_chain;
}
}
return (NULL);
}
void addreloc(struct Section *cs,struct Section *rs,uint32 id,
uint32 offset,uint8 rtype,int32 addend)
/* add a relocation to the specified section */
{
struct Reloc *r = alloc(sizeof(struct Reloc));
if (rs)
r->relocsect.ptr = rs;
else
r->relocsect.id = id;
r->offset = (unsigned long)offset;
r->addend = addend;
r->type = rtype;
addtail(&cs->relocs,&r->n); /* add to current section's Reloc list */
}
void addxref(struct GlobalVars *gv,struct Section *s,char *name,
uint32 offset,uint8 rtype,uint8 size,int32 addend)
/* add external symbol reference */
{
struct XReference *xref = alloczero(sizeof(struct XReference));
xref->name = name;
xref->offset = (unsigned long)offset;
xref->type = rtype;
xref->size = size;
xref->addend = addend;
addtail(&s->xrefs,&xref->n);
if (trace_sym_access(gv,name))
fprintf(stderr,"Symbol %s referenced in %s\n",name,getobjname(s->obj));
}
int32 readsection(struct GlobalVars *gv,uint8 *p,uint8 rtype)
/* Read 8-, 16- or 32-bit word from a section. The data-width is */
/* determined from the relocation type rtype. */
{
int32 v;
char be = gv->big_endian;
switch (rtype) {
case R_REL8:
case R_BASEREL8:
v = (int32)*p;
break;
case R_ADDR14: /* PowerPC */
case R_ADDR14_BRTAKEN:
case R_ADDR14_BRNTAKEN:
case R_REL14:
case R_REL14_BRTAKEN:
case R_REL14_BRNTAKEN:
v = (int32)read16(be,p) & 0xfffffffc;
break;
case R_ADDR16:
case R_ADDR16_LO:
case R_ADDR16_HI:
case R_ADDR16_HA:
case R_REL16:
case R_BASEREL16:
v = (int32)read16(be,p);
break;
case R_ADDR26: /* PowerPC */
case R_REL26:
case R_BASEREL26:
v = (int32)(read32(be,p) & 0x3fffffc);
if (v >= 0x2000000)
v = -v;
break;
default:
v = (int32)read32(be,p);
break;
}
return (v);
}
void writesection(struct GlobalVars *gv,uint8 *p,uint8 rtype,uint32 x)
/* Write a 8-, 16- or 32-bit word into a section. The data-width is */
/* determined from the relocation type rtype. */
{
char be = gv->big_endian;
switch (rtype) {
case R_REL8:
case R_BASEREL8:
*p = (uint8)x;
break;
case R_ADDR14: /* PowerPC */
case R_ADDR14_BRTAKEN:
case R_ADDR14_BRNTAKEN:
case R_REL14:
case R_REL14_BRTAKEN:
case R_REL14_BRNTAKEN:
write16(be,p,(read16(be,p) & 3) | (uint16)(x & 0xfffc));
break;
case R_ADDR16:
case R_ADDR16_LO:
case R_ADDR16_HI:
case R_ADDR16_HA:
case R_REL16:
case R_BASEREL16:
write16(be,p,(uint16)(x & 0xffff));
break;
case R_ADDR26: /* PowerPC */
case R_REL26:
case R_BASEREL26:
write32(be,p,(read32(be,p) & 0xfc000000) | (x & 0x3ffffff));
break;
default:
write32(be,p,x);
break;
}
}
uint8 relocsize(uint8 rtype)
/* determine size of relocation in bytes for the specified reloc type */
{
switch (rtype) {
case R_REL8:
case R_BASEREL8:
return (1);
case R_ADDR14:
case R_ADDR14_BRTAKEN:
case R_ADDR14_BRNTAKEN:
case R_REL14:
case R_REL14_BRTAKEN:
case R_REL14_BRNTAKEN:
case R_ADDR16:
case R_ADDR16_LO:
case R_ADDR16_HI:
case R_ADDR16_HA:
case R_REL16:
case R_BASEREL16:
return (2);
case R_ADDR26:
case R_REL26:
case R_BASEREL26:
return (3);
}
return (4);
}
struct Section *create_section(struct ObjectUnit *ou,char *name,
uint8 *data,unsigned long size)
/* creates and initializes a Section node */
{
static char *noname = "";
static uint32 idcnt = 0;
struct Section *s = alloczero(sizeof(struct Section));
if (name)
s->name = name;
else
s->name = noname;
s->data = data;
s->size = size;
s->obj = ou;
s->id = idcnt++;
initlist(&s->relocs); /* empty relocation list */
initlist(&s->xrefs); /* empty external references list */
return (s);
}
struct Section *find_sect_type(struct ObjectUnit *ou,uint8 type,uint8 prot)
/* find a section in current object unit with approp. type and protection */
{
struct Section *sec = (struct Section *)ou->sections.first;
struct Section *nextsec;
while (nextsec = (struct Section *)sec->n.next) {
if (sec->type==type && (sec->protection&prot)==prot)
return (sec);
sec = nextsec;
}
return (NULL);
}
struct Section *find_sect_id(struct ObjectUnit *ou,uint32 id)
/* find a section by its identification value */
{
struct Section *sec = (struct Section *)ou->sections.first;
struct Section *nextsec;
while (nextsec = (struct Section *)sec->n.next) {
if (sec->id == id)
return (sec);
sec = nextsec;
}
return (NULL);
}
struct LinkedSection *find_lnksec(struct GlobalVars *gv,char *name,
uint8 type,uint8 flags,uint8 fmask)
/* Return pointer to the first section which fits the passed */
/* name-, type- and flags-conditions. If a condition is 0, then */
/* it is ignored. If no appropriate section was found, return NULL. */
{
struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
struct LinkedSection *nextls;
while (nextls = (struct LinkedSection *)ls->n.next) {
bool found = TRUE;
if (name)
if (strcmp(ls->name,name))
found = FALSE;
if (type)
if (ls->type != type)
found = FALSE;
if (fmask)
if ((ls->flags&fmask) != (flags&fmask))
found = FALSE;
if (found)
return (ls);
ls = nextls;
}
return (NULL);
}
struct LinkedSection *smalldata_section(struct GlobalVars *gv)
/* Return pointer to first small data LinkedSection. If not existing, */
/* return first data/bss section or the first section. */
{
struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
struct LinkedSection *ldls=NULL,*nextls;
while (nextls = (struct LinkedSection *)ls->n.next) {
if (ls->type==ST_DATA || ls->type==ST_UDATA && ldls==NULL)
ldls = ls;
if (ls->flags & SF_SMALLDATA) /* first SD section found! */
return (ls);
ls = nextls;
}
return (ldls?ldls:((struct LinkedSection *)gv->lnksec.first));
}
void add_objunit(struct GlobalVars *gv,struct ObjectUnit *ou,bool fixrelocs)
/* adds an ObjectUnit to the approriate list */
{
if (ou) {
switch (ou->lnkfile->type) {
case ID_OBJECT:
case ID_EXECUTABLE:
addtail(&gv->selobjects,&ou->n);
add_priptrs(gv,ou);
break;
case ID_LIBARCH:
addtail(&gv->libobjects,&ou->n);
break;
case ID_SHAREDOBJ:
addtail(&gv->sharedobjects,&ou->n);
break;
default:
ierror("add_objunit(): Link File type = %d",
(int)ou->lnkfile->type);
}
if (fixrelocs) { /* convert section index into address */
struct Section *sec = (struct Section *)ou->sections.first;
struct Section *nextsec;
while (nextsec = (struct Section *)sec->n.next) {
struct Reloc *r = (struct Reloc *)sec->relocs.first;
struct Reloc *nextr;
while (nextr = (struct Reloc *)r->n.next) {
r->relocsect.ptr = getsecptr(&ou->sections,r->relocsect.id);
r = nextr;
}
sec = nextsec;
}
}
}
}
static struct Section *getsecptr(struct list *seclist,uint32 index)
/* return pointer to i. section in list */
{
int i = (int)index;
struct Section *s = (struct Section *)seclist->first;
struct Section *nexts;
while (i--) {
if (s->n.next == NULL)
ierror("getsecptr(): Not enough sections in list for index=%u",index);
else
s = (struct Section *)s->n.next;
}
return (s);
}
struct ObjectUnit *create_objunit(struct LinkFile *lf,char *objname)
/* creates and initializes an ObjectUnit node */
{
struct ObjectUnit *ou = alloc(sizeof(struct ObjectUnit));
static char *noname="";
ou->lnkfile = lf;
if (objname)
ou->objname = objname;
else
ou->objname = noname;
initlist(&ou->sections); /* empty section list */
ou->objsyms = alloc_hashtable(OBJSYMHTABSIZE);
ou->flags = 0;
initlist(&ou->pripointers); /* empty PriPointer list */
return (ou);
}
struct ObjectUnit *art_objunit(char *n,uint8 *d,unsigned long len,uint8 fmt)
/* creates and initializes an artificial linker-object */
{
struct LinkFile *lf = alloczero(sizeof(struct LinkFile));
lf->pathname = lf->filename = lf->objname = n;
lf->data = d;
lf->length = len;
lf->format = fmt;
lf->type = ID_ARTIFICIAL;
return (create_objunit(lf,n));
}
void new_priptr(struct ObjectUnit *ou,char *objname,char *sec,int pri,
char *xref,uint32 addend)
/* Inserts a new longword into the object's PriPointers list. */
{
struct PriPointer *newpp = alloc(sizeof(struct PriPointer));
newpp->objname = objname;
newpp->secname = sec;
newpp->priority = pri;
newpp->xrefname = xref;
newpp->addend = addend;
addtail(&ou->pripointers,&newpp->n);
}
void add_priptrs(struct GlobalVars *gv,struct ObjectUnit *ou)
/* Inserts all PriPointer nodes of an object into the global list. */
/* The node's position depends on 1. object name, 2. section name, */
/* 3. priority. */
{
struct PriPointer *newpp,*nextpp,*pp;
while (newpp = (struct PriPointer *)remhead(&ou->pripointers)) {
pp = (struct PriPointer *)gv->pripointers.first;
while (nextpp = (struct PriPointer *)pp->n.next) {
int c;
if ((c = strcmp(newpp->objname,pp->objname)) > 0)
break;
if (!c) {
if ((c = strcmp(newpp->secname,pp->secname)) > 0)
break;
if (!c && newpp->priority < pp->priority)
break;
}
pp = nextpp;
}
if (pp->n.pred)
insertbefore(&newpp->n,&pp->n);
else
addhead(&gv->pripointers,&newpp->n); /* first node in list */
}
}
void make_priptr_objects(struct GlobalVars *gv)
/* Make artificial objects from PriPointer list entries. */
/* This function usually has to be called *before* linker_resolve(). */
{
struct PriPointer *pp = (struct PriPointer *)gv->pripointers.first;
struct PriPointer *nextpp,*firstpp = pp;
unsigned long len = 0;
uint32 *data;
struct ObjectUnit *ou = NULL;
struct Section *s = NULL;
char be = gv->big_endian;
while (nextpp = (struct PriPointer *)pp->n.next) {
if (!ou) {
int scmp = strcmp(pp->objname,firstpp->objname);
if (!scmp) {
len += sizeof(uint32);
if (nextpp->n.next) {
if (strcmp(pp->secname,nextpp->secname))
/* include -1 word and terminating NULL pointer */
len += 2*sizeof(uint32);
}
else {
/* include -1 word and terminating NULL pointer */
len += 2*sizeof(uint32);
scmp = 1;
pp = nextpp;
}
}
if (scmp) {
data = alloczero(len);
ou = art_objunit(firstpp->objname,(uint8 *)data,len,gv->dest_format);
nextpp = firstpp; /* begin with first node of same object again */
firstpp = pp;
}
}
else {
if (pp != firstpp) {
/* The standard in most file formats is to start with the */
/* number of function pointers, or with a -1 */
if (!s) {
s = add_data_section(gv,ou,pp->secname,(uint8 *)data,
2*sizeof(uint32));
*data++ = 0xffffffff;
}
else if (strcmp(pp->secname,s->name)) {
s = add_data_section(gv,ou,pp->secname,(uint8 *)(++data),
2*sizeof(uint32));
*data++ = 0xffffffff;
}
write32(be,(uint8 *)data,pp->addend);
++data;
if (pp->xrefname)
addxref(gv,s,pp->xrefname,s->size-sizeof(uint32),R_ADDR32,
sizeof(uint32),pp->addend);
s->size += sizeof(uint32);
}
if (pp == firstpp || !nextpp->n.next) {
ou->lnkfile->type = ID_OBJECT;
add_objunit(gv,ou,FALSE);
ou = NULL;
s = NULL;
len = 0;
nextpp = firstpp; /* loop for next object unit */
}
}
pp = nextpp;
}
}
static struct Section *add_data_section(struct GlobalVars *gv,
struct ObjectUnit *ou,char *name,
uint8 *data,unsigned long size)
{
struct Section *s = create_section(ou,name,data,size);
s->type = ST_DATA;
s->protection = SP_READ | SP_WRITE;
s->alignment = 2;
addtail(&ou->sections,&s->n);
/* If the section name starts with '_', define it as a global */
/* symbol which defines the section's base address. */
if (*name == '_') {
struct Symbol *realsym,*lnksym;
if (addsymbol(gv,s,name,0,SYM_RELOC,0,SYMI_OBJECT,SYMB_GLOBAL,0)) {
error(59,name); /* Can't define symbol as section label */
}
else if (lnksym = findlnksymbol(fff[gv->dest_format],name)) {
if (realsym = findsymbol(gv,name)) {
/* update a linker symbol, which has the same name */
lnksym->value = realsym->value;
lnksym->relsect = realsym->relsect;
lnksym->type = realsym->type;
lnksym->flags = realsym->flags | SYMF_LNKSYM;
lnksym->info = realsym->info;
lnksym->bind = realsym->bind;
lnksym->size = realsym->size;
}
}
}
return (s);
}
bool ar_init(struct ar_info *ai,char *p,unsigned long plen,char *name)
/* check for valid archive header and initialize ar_info, if successful */
{
/* check for "!<arch>\n" id */
if (plen<sizeof(struct ar_hdr) || strncmp(p,ARMAG,SARMAG))
return (FALSE);
memset(ai,0,sizeof(struct ar_hdr));
ai->arname = name;
ai->next = (struct ar_hdr *)(p+SARMAG);
ai->arlen = plen - SARMAG;
return (TRUE);
}
bool ar_extract(struct ar_info *ai)
/* fill ar_info structure with informations about the next */
/* archive member */
{
struct ar_hdr *ah;
uint8 *p;
bool cont;
unsigned long size;
do {
cont = FALSE;
if (ai->next==NULL || ai->arlen<sizeof(struct ar_hdr))
return (FALSE); /* archive ends here */
ah = ai->next;
p = ((uint8 *)ah) + sizeof(struct ar_hdr);
ai->arlen -= sizeof(struct ar_hdr);
ai->name[0] = 0;
sscanf(ah->ar_size,"%lu",&ai->size); /* file size */
if (!strncmp(ah->ar_name,"/ ",2) || /* GNU symbol table */
!strncmp(ah->ar_name,"__.SYMDEF ",10)) /* BSD symbol table */
cont = TRUE;
if (!strncmp(ah->ar_name,"// ",3)) { /* GNU long names */
ai->long_names = p;
cont = TRUE;
}
if (ai->long_names && ah->ar_name[0]=='/' && /* long name (GNU) */
(ah->ar_name[1]>='0' && ah->ar_name[1]<='9')) {
int i,offset;
char c,*s,*d=ai->name;
sscanf(&ah->ar_name[1],"%d",&offset); /* name offset */
s = ai->long_names + offset;
for (i=0; i<MAXARNAME; i++) {
c = *s++;
if (c==0 || c=='/' || c=='\n')
break;
*d++ = c;
}
*d = 0;
}
else if (!strncmp(ah->ar_name,"#1/",3)) { /* ext. name fmt. #1 (BSD) */
int d,len;
sscanf(&ah->ar_name[3],"%d",&d); /* ext.fmt. name length */
if (d > ai->arlen)
error(37,ai->arname,ai->name); /* Malformatted archive member */
len = (d>MAXARNAME) ? MAXARNAME : d;
memcpy(ai->name,p,len);
ai->name[len] = 0;
if (d & 1)
++d; /* align to even offset */
p += d; /* set real beginning of file and size */
ai->size -= d;
ai->arlen -= d;
}
else { /* normal file name <= 16 chars */
char *n = &ah->ar_name[16];
int len;
for (len=16; len>0; len--)
if (*(--n) != ' ')
break;
if (len && *n=='/') /* GNU */
--len;
memcpy(ai->name,ah->ar_name,len);
ai->name[len] = 0;
}
if (strncmp(ah->ar_fmag,ARFMAG,2))
error(42,ai->arname,ai->name); /* consistency check failed */
ai->header = ah;
ai->data = p;
size = (ai->size&1) ? (ai->size+1) : ai->size;
ai->next = (struct ar_hdr *)(p + size);
if ((long)(ai->arlen -= size) < 0)
error(37,ai->arname,ai->name); /* Malformatted archive member */
}
while (cont);
return (TRUE);
}